﻿@page "/filedialog"
@implements IAsyncDisposable
@inject IJSRuntime JS
@using CommunityToolkit.Maui.Alerts;
@using CommunityToolkit.Maui.Core;
@using CommunityToolkit.Maui.Storage
@using System.Text;
@using System.Diagnostics;
@inject IFileSaver fileSaver
@inject IFolderPicker folderPicker

<h3>打开本机文件和目录对话框</h3>

<ul class="list-group">
    <li class="list-group-item">
        <button type="button" class="btn btn-primary btn-sm" @onclick=SaveAsTxtFileByJavaScript>
            <span class="oi oi-file me-2"></span>
            另存为txt文件(JavaScript)
        </button>
    </li>
    <li class="list-group-item">
        <button type="button" class="btn btn-primary btn-sm" @onclick=SaveAsTxtFileByToolkit>
            <span class="oi oi-file me-2"></span>
            另存为txt文件(CommunityToolkit)
        </button>
    </li>
    <li class="list-group-item">
        <button type="button" class="btn btn-primary btn-sm" @onclick=OpenTxtFileByJavaScript>
            <span class="oi oi-document me-2"></span>
            打开txt文件(JavaScript)
        </button>
    </li>
    <li class="list-group-item">
        <div class="input-group-btn btn btn-primary btn-sm">
            <label for="openTxtFile">
                <span class="oi oi-document me-2"></span>
                打开txt文件(BlazorInputFile)
            </label>
            <InputFile id="openTxtFile" style="display: none" accept='text/plain' OnChange=BlazorInputFile_OnChange />
        </div>
    </li>
    <li class="list-group-item">
        <button type="button" class="btn btn-primary btn-sm" @onclick=GetTxtFileFromSelectDirectoryByJavaScript>
            <span class="oi oi-folder me-2"></span>
            获取选择目录下的txt文件(JavaScript)
        </button>
    </li>
    <li class="list-group-item">
        <button type="button" class="btn btn-primary btn-sm" @onclick=GetTxtFileFromSelectDirectoryByToolkit>
            <span class="oi oi-folder me-2"></span>
            获取选择目录下的txt文件(CommunityToolkit)
        </button>
    </li>
</ul>

<textarea class="m-2" style="height:100px;" @bind=message></textarea>

<div class="list-group">
    @foreach (var txtFileInfo in txtFileInfoes)
    {
        <a href="/filedialog" class="list-group-item list-group-item-action d-flex justify-content-between mb-1" @onclick="((e) => LoadTxtFileFromSelectDirectory(txtFileInfo.Filename))">
            <strong>@txtFileInfo.Filename</strong>
            <small>@($"{txtFileInfo.Size:N0}字节")</small>
        </a>
    }
</div>

@code {

    private IJSObjectReference? module;
    private string message = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}, 你好，MAUI Blaor";
    private CancellationTokenSource? cts;

    record TxtFileInfo(string Filename, int Size);
    private TxtFileInfo[] txtFileInfoes = Array.Empty<TxtFileInfo>();
    private bool isSelectByJavaScript = true;
    private FileInfo[] FileInfoes = Array.Empty<FileInfo>();

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        base.OnAfterRender(firstRender);

        if (firstRender)
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", "./js/filedialog.js");
        }
    }

    //另存为txt文件(JavaScript)
    private async void SaveAsTxtFileByJavaScript()
    {
        string filename = $"{DateTimeOffset.Now:yyyyMMdd-HHmmss}.txt";

        try
        {
            //另存为txt文件，默认utf8
            await module!.InvokeVoidAsync("SaveAsTxtFile", filename, message);
        }
        catch (Exception ex)
        {
            message = $"SaveAsTxtFileByJavaScript出错: {ex.Message}";
        }
    }

    //另存为txt文件(CommunityToolkit)
    private async Task SaveAsTxtFileByToolkit()
    {
        cts = new CancellationTokenSource();
        CancellationToken cancellationToken = cts.Token;

        string filename = $"{DateTimeOffset.Now:yyyyMMdd-HHmmss}.txt";

        using var stream = new MemoryStream(Encoding.UTF8.GetBytes(message));

        var fileSaverResult = await fileSaver.SaveAsync(filename, stream, cancellationToken);

        if (fileSaverResult.IsSuccessful)
        {
            await Toast.Make($"The file was saved successfully to location: {fileSaverResult.FilePath}").Show(cancellationToken);
        }
        else
        {
            await Toast.Make($"The file was not saved successfully with error: {fileSaverResult.Exception.Message}").Show(cancellationToken);
        }
    }

    //打开txt文件(JavaScript)
    private async void OpenTxtFileByJavaScript()
    {
        try
        {
            //打开txt文件，默认utf8
            message = await module!.InvokeAsync<string>("OpenTxtFile");
        }
        catch (Exception ex)
        {
            message = $"OpenTxtFileByJavaScript出错: {ex.Message}";
        }

        await InvokeAsync(() => StateHasChanged());
    }

    //打开txt文件(BlazorInputFile)
    private async Task BlazorInputFile_OnChange(InputFileChangeEventArgs e)
    {
        if (e.File == null)
            return;

        string msg = $"Name={e.File.Name}, ContentType={e.File.ContentType}, Size={e.File.Size}";
        Debug.WriteLine(msg);

        if (e.File.Size > 512000)
        {
            message = $"文件{e.File.Name}长度{e.File.Size}超限";
        }
        else
        {
            using var ms = new MemoryStream();

            //读取文件，默认最大512k
            using var stream = e.File.OpenReadStream();
            await stream.CopyToAsync(ms);

            message = System.Text.Encoding.UTF8.GetString(ms.ToArray());
        }

        await InvokeAsync(() => StateHasChanged());
    }

    //获取选择目录下的txt文件(JavaScript)
    private async void GetTxtFileFromSelectDirectoryByJavaScript()
    {
        try
        {
            //获取选择目录下的txt文件
            txtFileInfoes = await module!.InvokeAsync<TxtFileInfo[]>("GetTxtFileFromSelectDirectory");

            isSelectByJavaScript = true;
        }
        catch (Exception ex)
        {
            message = $"GetTxtFileFromSelectDirectoryByJavaScript出错: {ex.Message}";
        }

        await InvokeAsync(() => StateHasChanged());
    }

    //从选择的目录中加载txt文件
    private async void LoadTxtFileFromSelectDirectory(string txtFilename)
    {
        try
        {
            if (isSelectByJavaScript)
            {
                //从选择的目录中加载txt文件
                message = await module!.InvokeAsync<string>("LoadTxtFileFromSelectDirectory", txtFilename);
            }
            else
            {
                var fileInfo = FileInfoes.FirstOrDefault(x => x.Name == txtFilename);
                if (fileInfo is null)
                {
                    message = "文件不存在";
                }
                else
                {
                    message = await File.ReadAllTextAsync(fileInfo.FullName);
                }
            }
        }
        catch (Exception ex)
        {
            message = $"LoadTxtFileFromSelectDirectory出错: {ex.Message}";
        }

        await InvokeAsync(() => StateHasChanged());
    }

    //获取选择目录下的txt文件(CommunityToolkit)
    private async Task GetTxtFileFromSelectDirectoryByToolkit()
    {
        cts = new CancellationTokenSource();
        CancellationToken cancellationToken = cts.Token;

        var result = await folderPicker.PickAsync(cancellationToken);
        if (result.IsSuccessful)
        {
            await Toast.Make($"The folder was picked: Name - {result.Folder.Name}, Path - {result.Folder.Path}", ToastDuration.Long).Show(cancellationToken);
        }
        else
        {
            await Toast.Make($"The folder was not picked with error: {result.Exception.Message}").Show(cancellationToken);
            return;
        }

        var dirInfo = new DirectoryInfo(result.Folder.Path);

        FileInfoes = dirInfo.GetFiles("*.txt");

        txtFileInfoes = FileInfoes.Select(x => new TxtFileInfo(x.Name, (int)x.Length)).ToArray();

        isSelectByJavaScript = false;

        await InvokeAsync(() => StateHasChanged());
    }

    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            await module.DisposeAsync();
        }
    }
}
